//! Pattern matching parsing

use super::Parser;
use crate::ast::expr::*;
use crate::error::{CompilerError, Result};
use crate::lexer::token::Token;

/// Parse pattern with OR support (1|2|3)
pub fn parse_pattern_or(parser: &mut Parser) -> Result<Option<Pattern>> {
    let mut patterns = Vec::new();

    if let Some(pattern) = parse_pattern_primary(parser)? {
        patterns.push(pattern);

        // Parse additional patterns separated by |
        while parser.consume(&Token::Pipe)? {
            if let Some(pattern) = parse_pattern_primary(parser)? {
                patterns.push(pattern);
            } else {
                return Err(CompilerError::syntax(
                    parser.current_location().line,
                    parser.current_location().column,
                    "Expected pattern after '|'",
                ));
            }
        }

        // If we have multiple patterns, create an Or pattern
        if patterns.len() > 1 {
            Ok(Some(Pattern::Or(patterns)))
        } else {
            Ok(Some(patterns.into_iter().next().unwrap()))
        }
    } else {
        Ok(None)
    }
}

/// Parse primary pattern (without OR)
pub fn parse_pattern_primary(parser: &mut Parser) -> Result<Option<Pattern>> {
    if parser.is_at_end() {
        return Ok(None);
    }

    match parser.peek() {
        Some(token) => match &token.token {
            Token::Integer(n) => {
                let n = *n;
                parser.advance()?;
                Ok(Some(Pattern::Literal(Literal::Integer(n))))
            }
            Token::Float(f) => {
                let f = *f;
                parser.advance()?;
                Ok(Some(Pattern::Literal(Literal::Float(f))))
            }
            Token::String(s) => {
                let s = s.clone();
                parser.advance()?;
                Ok(Some(Pattern::Literal(Literal::String(s))))
            }
            Token::Char(c) => {
                let c = *c;
                parser.advance()?;
                Ok(Some(Pattern::Literal(Literal::Char(c))))
            }
            Token::True => {
                parser.advance()?;
                Ok(Some(Pattern::Literal(Literal::Boolean(true))))
            }
            Token::False => {
                parser.advance()?;
                Ok(Some(Pattern::Literal(Literal::Boolean(false))))
            }
            Token::Identifier(name) => {
                let name = name.clone();
                let location = parser.current_location();
                parser.advance()?;

                // Check if this is an enum pattern (e.g., Result::Ok(value))
                if parser.consume(&Token::ColonColon)? {
                    // This is a path-style pattern: EnumName::VariantName(...)
                    let enum_name = name;

                    if let Some(Token::Identifier(variant_name)) = parser.peek().map(|t| &t.token) {
                        let variant_name = variant_name.clone();
                        parser.advance()?;

                        parse_enum_variant_pattern(parser, enum_name, variant_name, location)
                    } else {
                        Err(CompilerError::syntax(
                            parser.current_location().line,
                            parser.current_location().column,
                            "Expected variant name after '::'",
                        ))
                    }
                } else if let Some((enum_name, variant_name)) = shorthand_enum_variant(&name) {
                    // Handle shorthand Option/Result variants like Some/None/Ok/Err
                    parse_enum_variant_pattern(
                        parser,
                        enum_name.to_string(),
                        variant_name.to_string(),
                        location,
                    )
                } else {
                    // Simple variable pattern
                    Ok(Some(Pattern::Variable(name)))
                }
            }
            Token::Underscore => {
                parser.advance()?;
                Ok(Some(Pattern::Wildcard))
            }
            Token::LeftParen => {
                parser.advance()?;
                let mut patterns = Vec::new();

                if !parser.check(&Token::RightParen) {
                    loop {
                        if let Some(pattern) = parse_pattern_or(parser)? {
                            patterns.push(pattern);
                        }

                        if !parser.consume(&Token::Comma)? {
                            break;
                        }
                    }
                }

                parser.expect(&Token::RightParen)?;
                Ok(Some(Pattern::Tuple(patterns)))
            }
            _ => Ok(None),
        },
        None => Ok(None),
    }
}

fn shorthand_enum_variant(name: &str) -> Option<(&'static str, &'static str)> {
    match name {
        "Some" => Some(("Option", "Some")),
        "None" => Some(("Option", "None")),
        "Ok" => Some(("Result", "Ok")),
        "Err" => Some(("Result", "Err")),
        _ => None,
    }
}

fn parse_enum_variant_pattern(
    parser: &mut Parser,
    enum_name: String,
    variant_name: String,
    location: crate::error::Location,
) -> Result<Option<Pattern>> {
    if parser.consume(&Token::LeftParen)? {
        let mut patterns = Vec::new();

        if !parser.check(&Token::RightParen) {
            loop {
                if let Some(pattern) = parse_pattern_or(parser)? {
                    patterns.push(pattern);
                }

                if !parser.consume(&Token::Comma)? {
                    break;
                }
            }
        }

        parser.expect(&Token::RightParen)?;

        Ok(Some(Pattern::Enum(EnumPattern {
            enum_name,
            variant_name,
            patterns,
            location,
        })))
    } else {
        Ok(Some(Pattern::Enum(EnumPattern {
            enum_name,
            variant_name,
            patterns: vec![],
            location,
        })))
    }
}
